using System;
using System.Web;
using System.Net;
using System.IO;
using System.Collections.Specialized;

namespace TeamDoer.Helpers
{
	public class oAuthTwitter : OAuthBase
	{
		public enum Method { GET, POST, DELETE };
		public const string REQUEST_TOKEN = "http://twitter.com/oauth/request_token";
		public const string AUTHORIZE = "http://twitter.com/oauth/authorize";
		public const string ACCESS_TOKEN = "http://twitter.com/oauth/access_token";

		public string ConsumerKey 
		{
			get;set;
		}

		public string ConsumerSecret
		{
			get;set;
		}

		public string Token { get; set; }
		public string TokenSecret { get; set; }
		public string CallBackUrl { get; set; }
		public string OAuthVerifier { get; set; }

		/// <summary>
		/// Get the link to Twitter's authorization page for this application.
		/// </summary>
		/// <returns>The url with a valid request token, or a null string.</returns>
		public string AuthorizationLinkGet()
		{
			string ret = null;

			string response = oAuthWebRequest(Method.GET, REQUEST_TOKEN, String.Empty);
			if (response.Length > 0)
			{
				//response contains token and token secret.  We only need the token.
				NameValueCollection qs = HttpUtility.ParseQueryString(response);

				if (qs["oauth_callback_confirmed"] != null)
				{
					if (qs["oauth_callback_confirmed"] != "true")
					{
						throw new Exception("OAuth callback not confirmed.");
					}
				}

				if (qs["oauth_token"] != null)
				{
					ret = AUTHORIZE + "?oauth_token=" + qs["oauth_token"];
				}
			}
			return ret;
		}

		/// <summary>
		/// Exchange the request token for an access token.
		/// </summary>
		/// <param name="authToken">The oauth_token is supplied by Twitter's authorization page following the callback.</param>
		/// <param name="oauthVerifier">An oauth_verifier parameter is provided to the client either in the pre-configured callback URL</param>
		public void AccessTokenGet(string authToken, string oauthVerifier)
		{
			this.Token = authToken;
			this.OAuthVerifier = oauthVerifier;

			string response = oAuthWebRequest(Method.GET, ACCESS_TOKEN, String.Empty);

			if (response.Length > 0)
			{
				//Store the Token and Token Secret
				NameValueCollection qs = HttpUtility.ParseQueryString(response);
				if (qs["oauth_token"] != null)
				{
					this.Token = qs["oauth_token"];
				}
				if (qs["oauth_token_secret"] != null)
				{
					this.TokenSecret = qs["oauth_token_secret"];
				}
			}
		}
		
		/// <summary>
		/// Submit a web request using oAuth.
		/// </summary>
		/// <param name="method">GET or POST</param>
		/// <param name="url">The full url, including the querystring.</param>
		/// <param name="postData">Data to post (querystring format)</param>
		/// <returns>The web server response.</returns>
		public string oAuthWebRequest(Method method, string url, string postData)
		{
			string outUrl = "";
			string querystring = "";
			string ret = "";


			//Setup postData for signing.
			//Add the postData to the querystring.
			if (method == Method.POST || method == Method.DELETE)
			{
				if (postData.Length > 0)
				{
					//Decode the parameters and re-encode using the oAuth UrlEncode method.
					NameValueCollection qs = HttpUtility.ParseQueryString(postData);
					postData = "";
					foreach (string key in qs.AllKeys)
					{
						if (postData.Length > 0)
						{
							postData += "&";
						}
						qs[key] = HttpUtility.UrlDecode(qs[key]);
						qs[key] = this.UrlEncode(qs[key]);
						postData += key + "=" + qs[key];

					}
					if (url.IndexOf("?") > 0)
					{
						url += "&";
					}
					else
					{
						url += "?";
					}
					url += postData;
				}
			}

			Uri uri = new Uri(url);
			
			string nonce = this.GenerateNonce();
			string timeStamp = this.GenerateTimeStamp();

			//Generate Signature
			string sig = this.GenerateSignature(uri,
				this.ConsumerKey,
				this.ConsumerSecret,
				this.Token,
				this.TokenSecret,
				this.CallBackUrl,
				this.OAuthVerifier,
				method.ToString(),
				timeStamp,
				nonce,
				out outUrl,
				out querystring);

			querystring += "&oauth_signature=" + this.UrlEncode(sig);

			//Convert the querystring to postData
			if (method == Method.POST || method == Method.DELETE)
			{
				postData = querystring;
				querystring = "";
			}

			if (querystring.Length > 0)
			{
				outUrl += "?";
			}

			ret = WebRequest(method, outUrl +  querystring, postData);

			return ret;
		}

		/// <summary>
		/// Web Request Wrapper
		/// </summary>
		/// <param name="method">Http Method</param>
		/// <param name="url">Full url to the web resource</param>
		/// <param name="postData">Data to post in querystring format</param>
		/// <returns>The web server response.</returns>
		public string WebRequest(Method method, string url, string postData)
		{
			HttpWebRequest webRequest = null;
			StreamWriter requestWriter = null;
			string responseData = "";

			webRequest = System.Net.WebRequest.Create(url) as HttpWebRequest;
			webRequest.Method = method.ToString();
			webRequest.ServicePoint.Expect100Continue = false;
			//webRequest.UserAgent  = "Identify your application please.";
			//webRequest.Timeout = 20000;

			if (method == Method.POST || method == Method.DELETE)
			{
				webRequest.ContentType = "application/x-www-form-urlencoded";

				//POST the data.
				requestWriter = new StreamWriter(webRequest.GetRequestStream());
				try
				{
					requestWriter.Write(postData);
				}
				catch
				{
					throw;
				}
				finally
				{
					requestWriter.Close();
					requestWriter = null;
				}
			}

			responseData = WebResponseGet(webRequest);

			webRequest = null;

			return responseData;

		}

		/// <summary>
		/// Process the web response.
		/// </summary>
		/// <param name="webRequest">The request object.</param>
		/// <returns>The response data.</returns>
		public string WebResponseGet(HttpWebRequest webRequest)
		{
			StreamReader responseReader = null;
			string responseData = "";

			try
			{
				responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream());
				responseData = responseReader.ReadToEnd();
			}
			catch
			{
				throw;
			}
			finally
			{
				webRequest.GetResponse().GetResponseStream().Close();
				responseReader.Close();
				responseReader = null;
			}

			return responseData;
		}
	}
}
